/*
    list.c.tst - Unit tests for the List, Link and MprStringList classes

    Copyright (c) All Rights Reserved. See details at the end of the file.
 */

/********************************** Includes **********************************/

#include    "testme.h"
#include    "mpr.h"

/*********************************** Locals ***********************************/

#define LIST_MAX_ITEMS      1000            /* Count of items to put in list */

/************************************ Code ************************************/

static void createList()
{
    MprList *lp;

    lp = mprCreateList(0, 0);
    ttrue(lp != 0);
}


static void isListEmpty()
{
    MprList     *lp;

    lp = mprCreateList(0, 0);
    ttrue(lp != 0);

    ttrue(mprGetListLength(lp) == 0);
    ttrue(mprGetFirstItem(lp) == 0);
}


static void insertAndRemove()
{
    MprList     *lp;
    int         index;

    lp = mprCreateList(0, 0);
    ttrue(lp != 0);

    /*
        Do one insert and remove 
     */
    index = mprAddItem(lp, (void*) 1);
    ttrue(index >= 0);
    ttrue(mprGetListLength(lp) == 1);

    mprRemoveItem(lp, (void*) 1);
    ttrue(mprGetListLength(lp) == 0);

    /*
        Test remove will compact
     */
    mprAddItem(lp, (void*) 1);
    mprAddItem(lp, (void*) 2);
    mprAddItem(lp, (void*) 3);

    mprRemoveItem(lp, (void*) 2);
    ttrue(mprGetListLength(lp) == 2);
    mprRemoveItem(lp, (void*) 3);
    ttrue(mprGetListLength(lp) == 1);
}


static void lotsOfInserts()
{
    MprList     *lp;
    int         i;

    lp = mprCreateList(LIST_MAX_ITEMS, 0);
    ttrue(lp != 0);

    /*
        Do lots insertions 
     */
    for (i = 0; i < LIST_MAX_ITEMS; i++) {
        mprAddItem(lp, (void*) (long) i);
        ttrue(mprGetListLength(lp) == (i + 1));
    }

    /*
        Now remove
     */
    for (i = LIST_MAX_ITEMS - 1; i >= 0; i--) {
        mprRemoveItem(lp, (void*) (long) i);
        ttrue(mprGetListLength(lp) == i);
    }
}


static void listIterate()
{
    MprList     *lp;
    int         max, i, item, next;

    max = 50;
    lp = mprCreateList(max, 0);
    ttrue(lp != 0);

    for (i = 0; i < max; i++) {
        mprAddItem(lp, (void*) (long) (i + 1));
    }
    i = next = 0;
    item = (int) (long) mprGetNextItem(lp, &next);
    while (item > 0) {
        i++;
        item = (int) (long) mprGetNextItem(lp, &next);
    }
    ttrue(i == max);


    /*
        Abbreviated form with no GetFirst
     */
    i = 0;
    next = 0;
    while ((item = (int) (long) mprGetNextItem(lp, &next)) != 0) {
        i++;
    }
    ttrue(i == max);
}


static void orderedInserts()
{
    MprList     *lp;
    int         i, item, next;

    lp = mprCreateList(0, 0);
    ttrue(lp != 0);

    /*
        Add items such that the final list is ordered
     */
    mprAddItem(lp, (void*) (long) 4);
    mprAddItem(lp, (void*) (long) 5);
    mprInsertItemAtPos(lp, 0, (void*) 2);
    mprInsertItemAtPos(lp, 0, (void*) 1);
    mprInsertItemAtPos(lp, 2, (void*) 3);
    mprAddItem(lp, (void*) (long) 6);

    i = 1;
    next = 0;
    item = (int) (long) mprGetNextItem(lp, &next);
    while (item > 0) {
        ttrue(item == i);
        i++;
        item = (int) (long) mprGetNextItem(lp, &next);
    }
}


static char *toString(char *items[], int nelt)
{
    MprBuf  *buf;
    int     i;

    buf = mprCreateBuf(0, 0);
    for (i = 0; i < nelt; i++) {
        mprPutToBuf(buf, "%s ", items[i]);
    }
    if (i > 0) {
        mprAdjustBufEnd(buf, -1);
    }
    return mprBufToString(buf);
}


#define NELT(items) (sizeof(items) / sizeof(char*))

static int sortNum(cchar **s1, cchar **s2)
{
    int     v1, v2;
    
    v1 = atoi(*s1);
    v2 = atoi(*s2);
    if (v1 < v2) {
        return -1;
    } else if (v1 > v2) {
        return 1;
    }
    return 0;
}

static void tsort(cchar *input, cchar *expect, MprSortProc cmp)
{
    char    *item, *tok;
    char    *items[16];
    int     count;

    tok = sclone(input);
    for (count = 0; count < NELT(items) && (item = stok(tok, " ", &tok)) != 0; count++) {
        items[count] = item;
    }
    mprSort(items, count, sizeof(char*), cmp, 0);
    if (!smatch(expect, toString(items, count))) {
        print("\nINPUT  \"%s\"", input);
        print("RESULT \"%s\"", toString(items, count));
    }
    ttrue(smatch(expect, toString(items, count)));
}


static void sort()
{
    tsort("", "", 0);
    tsort("0", "0", 0);
    tsort("0 1", "0 1", 0);
    tsort("1 0", "0 1", 0);
    tsort("1 1", "1 1", 0);

    tsort("0 1 2", "0 1 2", 0);
    tsort("0 2 1", "0 1 2", 0);
    tsort("2 1 0", "0 1 2", 0);
    tsort("2 0 1", "0 1 2", 0);
    tsort("1 2 0", "0 1 2", 0);
    tsort("1 0 2", "0 1 2", 0);

    tsort("0 1 2 3 4 5", "0 1 2 3 4 5", 0);
    tsort("5 4 3 2 1 0", "0 1 2 3 4 5", 0);
    tsort("5 1 0 2 4 3", "0 1 2 3 4 5", 0);

    //  Odd number of elements
    tsort("5 1 0 2 4 3 6", "0 1 2 3 4 5 6", 0);
    tsort("5 0 1", "0 1 5", 0);
    tsort("6 3 5 0 1", "0 1 3 5 6", 0);

    //  Even elements
    tsort("5 1 0 4 2 3", "0 1 2 3 4 5", 0);
    tsort("2 3 0 1", "0 1 2 3", 0);
    tsort("3 2 0 1", "0 1 2 3", 0);
    tsort("3 2 4 0 1", "0 1 2 3 4", 0);

    //  Even elements

    //  Repeats
    tsort("1 2 1 2 1 2", "1 1 1 2 2 2", 0);
    tsort("2 1 2 1 2 1", "1 1 1 2 2 2", 0);

    //  Numeric sorts
    tsort("25 13 7 10", "7 10 13 25", (MprSortProc) sortNum);
    tsort("25 13 16 31 44 7 31 48 48 105 10", "7 10 13 16 25 31 31 44 48 48 105", (MprSortProc) sortNum);
    tsort("-8 -2 0 7 44", "-8 -2 0 7 44", (MprSortProc) sortNum);
    tsort("44 -2 7 -8 0", "-8 -2 0 7 44", (MprSortProc) sortNum);
}


int main(int argc, char **argv)
{
    mprCreate(argc, argv, 0);
    createList();
    isListEmpty();
    insertAndRemove();
    lotsOfInserts();
    listIterate();
    orderedInserts();
    sort();
    return 0;
}

/*
    @copy   default

    Copyright (c) Embedthis Software. All Rights Reserved.

    This software is distributed under commercial and open source licenses.
    You may use the Embedthis Open Source license or you may acquire a 
    commercial license from Embedthis Software. You agree to be fully bound
    by the terms of either license. Consult the LICENSE.md distributed with
    this software for full details and other copyrights.

    Local variables:
    tab-width: 4
    c-basic-offset: 4
    End:
    vim: sw=4 ts=4 expandtab

    @end
 */
